#include <am.h>
#include <riscv/riscv.h>
#include <klib.h>

static Context* (*user_handler)(Event, Context*) = NULL;

Context* __am_irq_handle(Context *c) {
  if (user_handler) {
    Event ev = {0};
    switch (c->mcause) {
	  case 0xb: ev.event = EVENT_YIELD,c->mepc+=4;break;//debug:RISC需要在软件层面中+4
      default: ev.event = EVENT_ERROR; break;
    }
	//printf("TEST\n");
    c = user_handler(ev, c);
    assert(c != NULL);
  }

  return c;
}

extern void __am_asm_trap(void);

bool cte_init(Context*(*handler)(Event, Context*)) {
  // initialize exception entry
  asm volatile("csrw mtvec, %0" : : "r"(__am_asm_trap));//将入口地址传给了mtvec

  // register event handler
  user_handler = handler;

  return true;
}

//创建A进程的内核上下文、设置预设的返回地址到内核上下文-A进程自陷-...-A进程恢复（将内核上下文赋值给进程，地址返回到保存的入口地址）

//如果不切换上下文，则返回地址应该是自陷时的地址
//这里的场景是上下文切换，所以返回地址entry是一个回调函数，参数为arg
Context *kcontext(Area kstack, void (*entry)(void *), void *arg) {
	Context* ctx = kstack.end - sizeof(Context);//指向内核上下文的起始 
	ctx->mepc = (uintptr_t)entry;
	ctx->gpr[10] = (uintptr_t)arg;//gpr[10]==$a0
	//ctx->mstatus = 0x1800;//使difftest不报错
	return ctx;
}

void yield() {
#ifdef __riscv_e
  asm volatile("li a5, -1; ecall");//自陷时需要先设置寄存器，类似ebreak前设置a0
#else
  asm volatile("li a7, -1; ecall");
#endif
}

bool ienabled() {
  return false;
}

void iset(bool enable) {
}
